<?php
namespace Swostar\Foundation;

use Closure;
use Exception;
use Swostar\Event\Event;
use Swostar\Route\Route;
use Swostar\Container\Container;
use Swostar\Message\Http\Request;
use Swostar\Server\Http\HttpServer;
use Swostar\Server\WebSocket\WebSocketServer;


class Application extends Container
{
    protected const SWOOLE_WELCOME = "
         _     _ _     _     _   
        | |   | | |   | |   | |  
        | |__ | | |__ | |__ | |_ 
        | '_ \| | '_ \| '_ \| __|
        | | | | | |_) | |_) | |_ 
        |_| |_|_|_.__/|_.__/ \__|
    ";

    protected $basePath = '';

    public function __construct($basePath = null)
    {

        if (!empty($basePath)) {
            $this->setBasePath($basePath);
        }

        // 注册对象
        $this->registerBaseBindings();

        // 初始化
        $this->init();

    }


    /**
     * 启动方法
     * @param mixed $argv 命令行参数
     * @return void 
     */
    public function run($argv)
    {
        if (!isset($argv[1])) {
            echo "缺少启动参数 \n";
            exit; 
        }

        switch ($argv[1]) {
            case 'http:start':
                $server = new HttpServer($this);
                break;
            case 'ws:start':
                $server = new WebSocketServer($this);
                break;
            default:
                echo '启动失败' . PHP_EOL;
                exit;
        }

        echo self::SWOOLE_WELCOME;

        $server->start();
    }

    /**
     * 注册对象到容器中
     * @return void 
     */
    protected function registerBaseBindings()
    {
        // 设置当前容器为单例模式
        self::setInstance($this);

        $binds = $this->getBinds();
        if (!empty($binds)) {
            foreach ($binds as $abstract => $object) {
                $this->bind($abstract, $object);
            }
        }
    }

    /**
     * 路由、事件等初始化
     * @return void 
     */
    public function init()
    {
        
        // 路由初始化，路由注册，并将路由对象绑定到容器中
        // $this->bind('route', Route::getInstance()->registerRoute());
        
        // echo "<pre>";
        // print_r(Route::getInstance()->getRoutes());
        // echo "</pre>";
        // echo PHP_EOL;

        // 事件初始化，事件注册，并将事件对象绑定到容器中
        // $this->bind('event', $this->registerEvent);
        
    }

    /**
     * 获取所有事件方法，绑定到事件类中
     * @return Event 
     * @throws Exception 
     */
    protected function registerEvent()
    {
        $event = new Event();

        $dir = $this->getBasePath() . '/app/Listener';

        if (!is_dir($dir)) {
            return;
        }

        // 扫描用户配置的事件类
        $files = scandir($dir);

        if (empty($files)) {
            return;
        }

        foreach ($files as $key => $file) {
            if ($file === '.' || $file === '..') {
                continue;
            }
   
            // 读取文件
            $class = 'app\\Listener\\' . explode('.', $file)[0];
            
            if (!class_exists($class)) {
                throw new Exception($class . 'listener class not found', 500);
            }

            $class = new $class();

            if (!method_exists($class, 'run')) {
                throw new Exception('listener class no run method ', 500);
            }

            $event->register($class->getName(), [$class, 'run']);
        }
        
        return $event;
    }


    /**
     * 设置基础路径
     * @param mixed $basePath 
     * @return void 
     */
    public function setBasePath($basePath)
    {
        $this->basePath = $basePath;
    }

    /**
     * 获取基础路径
     * @return string 
     */
    public function getBasePath(): string
    {
        return $this->basePath;
    }


    /**
     * 获取初始注册入容器的对象
     * @return (Request|(Closure)[] 
     */
    protected function getBinds() 
    {
        return [
            // 配置方法对象，绑定到容器中
            'config' => (new \Swostar\Config\Config()),

            // http请求注册，绑定到容器中
            'httpRequest' => (new \Swostar\Message\Http\Request()),

            // 路由注册，并将事件对象绑定到容器中
            'route' => Route::getInstance()->registerRoute(),

            // 事件注册，并将事件对象绑定到容器中
            'event' => $this->registerEvent()
        ];
    }

}
